#include "db.h"

// 数据库配置信息
static std::string server = "127.0.0.1";
static std::string user = "root";
static std::string password = "123789";
static std::string dbname = "chat";


// 初始化数据库连接
MySQL::MySQL() : _conn(mysql_init(nullptr)), _stmt(nullptr) {}

// 释放数据库连接资源
MySQL::~MySQL() {
    if (_stmt != nullptr) mysql_stmt_close(_stmt);
    if (_conn != nullptr) mysql_close(_conn);
}
    

// 连接数据库
bool MySQL::connect() {
    if (MYSQL *p = mysql_real_connect(_conn, server.c_str(), user.c_str(), password.c_str(), dbname.c_str(), 3306, nullptr, 0)) {
        if (mysql_query(_conn, "SET NAMES utf8mb4") != 0) { // 使用更通用的字符编码
            LOG_ERROR << "Failed to set character encoding: " << mysql_error(_conn);
            return false;
        }
        LOG_INFO << "Connected to MySQL successfully!";
        return true;
    }
    else {
        LOG_ERROR << "Connect MySQL failed: " << mysql_error(_conn);
        return false;
    }
}

// 断开数据库连接
void MySQL::disconnect()
{
    if (_conn) {
        mysql_close(_conn);  // 关闭 MySQL 连接
        _conn = nullptr;     // 将连接指针设置为 nullptr，避免悬挂指针
    }
}

// 更新操作
bool MySQL::update(const std::string& sql) {
    if (mysql_query(_conn, sql.c_str()) != 0) {
        LOG_INFO << __FILE__ << ":" << __LINE__ << ": " << sql << " Update failure: " 
                 << mysql_error(_conn); // 添加错误信息
        return false;
    }
    return true;
}

// 获取插入操作后生成的主键
uint64_t MySQL::getLastInsertId()
{   
    MYSQL * conn = getConnection();
    return static_cast<uint64_t>(mysql_insert_id(conn));
}

// 查询操作
MYSQL_RES * MySQL::query(std::string sql) {
    if (mysql_query(_conn, sql.c_str()) != 0) {
        LOG_INFO << __FILE__ << ":" << __LINE__ << ":" << sql << "Query failure";
        return nullptr;
    }
    // return mysql_use_result(_conn); // 适合大结果集，不并行
    return mysql_store_result(_conn); // 适合小结果集， 一次性获取存储到内存中
}

// 获取连接句柄
MYSQL *MySQL::getConnection()
{
    if (_conn) {
        return _conn;
    }
    return nullptr;    
}

//获取最近发生的错误信息
unsigned int MySQL::getErrorCode() const
{
    if (_stmt) {
        // 如果有预处理语句，则返回它的错误代码
        return mysql_stmt_errno(_stmt);
    } else {
        // 否则返回连接级别的错误代码
        return mysql_errno(_conn);
    }
}

// 准备SQL语句
MYSQL_STMT* MySQL::prepare(const std::string &sql)
{
    if (!_conn) {
        LOG_ERROR << "Database connection is not established.";
        throw std::runtime_error("Database connection is not established.");
    }

    // 1. 初始化预处理语句
    _stmt = mysql_stmt_init(_conn);
    if (!_stmt) {
        LOG_ERROR << "Failed to initialize statement: " << mysql_error(_conn);
        throw std::runtime_error("Failed to initialize statement.");
    }

    // 2. 准备预处理语句
    if (mysql_stmt_prepare(_stmt, sql.c_str(), sql.size())) {
        LOG_ERROR << "Failed to prepare statement: " << mysql_stmt_error(_stmt);
        mysql_stmt_close(_stmt);  // 清理预处理语句对象
        _stmt = nullptr;
        throw std::runtime_error("Failed to prepare statement.");
    }
    return _stmt;
}

// 绑定参数
bool MySQL::bindParam(MYSQL_BIND *param)
{
    // 检查 _stmt 和 param 是否为非空
    if (_stmt == nullptr || param == nullptr) {
        LOG_ERROR << "Invalid statement or parameter.";
        return false;
    }

    // 确保预处理语句已准备好
    if (mysql_stmt_errno(_stmt) != 0) {
        LOG_ERROR << "Prepared statement is not in a valid state.";
        return false;
    }

    // 绑定参数到预处理语句
    if (mysql_stmt_bind_param(_stmt, param) != 0) {
        LOG_ERROR << "Binding parameters failed: " << mysql_stmt_error(_stmt);
        mysql_stmt_close(_stmt);
        _stmt = nullptr;    // 标记为已关闭
        return false;
    }

    // 绑定成功，返回 true
    return true;
}
 
// 绑定参数方法的重载
bool MySQL::bindParam(MYSQL_BIND *params, unsigned int paramCount)
{
    // 检查 _stmt 和 params 是否为非空
    if (_stmt == nullptr || params == nullptr) {
        LOG_ERROR << "Invalid statement or parameters.";
        return false;
    }

    // 确保预处理语句已准备好
    if (mysql_stmt_errno(_stmt) != 0) {
        LOG_ERROR << "Prepared statement is not in a valid state.";
        return false;
    }

    // 绑定参数到预处理语句
    if (mysql_stmt_bind_param(_stmt, params) != 0) {
        LOG_ERROR << "Binding parameters failed: " << mysql_stmt_error(_stmt);
        // 通知调用者预处理语句不再可用
        mysql_stmt_close(_stmt);
        _stmt = nullptr;
        return false;
    }

    // 绑定成功，返回 true
    return true;
}

// 执行预处理语句
bool MySQL::execute()
{
    // 执行预处理语句
    if (mysql_stmt_execute(_stmt)) {
        LOG_ERROR << "Execute failed:" << mysql_stmt_error(_stmt);

        // 如果你决定在这里关闭 _stmt，请确保设置它为 nullptr 并通知调用者
        mysql_stmt_close(_stmt);
        _stmt = nullptr;    // 标记为已关闭

        return false;
    }
    return true;
}

bool MySQL::closeStmt()
{
    if (_stmt != nullptr) {
        // 关闭预处理语句
        mysql_stmt_close(_stmt);
        _stmt = nullptr; // 标记为已关闭

        LOG_INFO << "Statement closed successfully.";
        return true;
    } else {
        LOG_WARN << "Attempting to close a statement that is already closed or not initialized.";
        return false;
    }
}

// 绑定结果集
bool MySQL::bindResult(MYSQL_BIND *result) {
    if (_stmt == nullptr || result == nullptr) {
        LOG_ERROR << "Invalid statement or result.";
        return false;
    }

    if (mysql_stmt_bind_result(_stmt, result) != 0) {
        LOG_ERROR << "Binding results failed: " << mysql_stmt_error(_stmt);
        return false;
    }

    return true;
}

// 获取结果
bool MySQL::fetch() {
    if (_stmt == nullptr) {
        LOG_ERROR << "Statement is not initialized.";
        return false;
    }

    int res = mysql_stmt_fetch(_stmt);
    if (res == MYSQL_NO_DATA) {
        // 没有更多数据
        return false;
    } else if (res != 0) {
        LOG_ERROR << "Fetching data failed: " << mysql_stmt_error(_stmt);
        return false;
    }

    return true;
}